/**
  ******************************************************************************
  * @file    backwork.c
  * @author  Dragon.Chen
  * @version V1.0.0
  * @date    09-22-2014
  * @brief   业务逻辑代码
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2013 上海今中网络科技有限公司 </center></h2>
  ******************************************************************************
  */

#include "backwork.h"

/**
  * @brief  master进程定时器超时处理(用于剔除用户)
  * @param  void
  * @retval void
  */
void master_timer_timeout()
{
    return;
}

/**
  * @brief  worker进程定时器超时处理无效socket
  * @param  void
  * @retval void
  */
void worker_timer_timeout()
{
    int msg;

    msg  = get_timer_size();
    timer_tick();
    msg -= get_timer_size();

    if (msg > 0)
    {
        ShmBusyRatioLock();
        snprintf(BusyRatioPtr[WorkerProcessIndex], SERVER_SHM_CT_PER_SIZE - 1, "%d",
                 WorkerProcess[WorkerProcessIndex].busyRatio);
        ShmBusyRatioUnlock();

        msg = MW_BUSY_RATIO;
        send(WorkerProcess[WorkerProcessIndex].pipefd[1], &msg, 1, 0); // 不关心发送成功与否
    }
}

/**
  * @brief  重读服务器配置文件
  * @param  arg1:工作进程数据
  * @retval void
  */
void worker_reread_config()
{
    free_server_config();
    get_server_config();
    get_rule_config(ServerConfig.rulePath);

//    free_stunnel_config();
//    free_openvpn_config();

//    get_stunnel_config(ServerConfig.stunnelPath);
//    get_openvpn_config(ServerConfig.openvpnPath);

    if (WORKER_LOGIN_TIMEOUT           < 2  || WORKER_LOGIN_TIMEOUT           > 5   )
        WORKER_LOGIN_TIMEOUT           = 3;
    if (WORKER_HEARTBEAT_TIMEOUT       < 30 || WORKER_HEARTBEAT_TIMEOUT       > 600 )
        WORKER_HEARTBEAT_TIMEOUT       = 30;
    if (MASTER_RECYCLE_WORKERS_MAXTIME < 60 || MASTER_RECYCLE_WORKERS_MAXTIME >600  )
        MASTER_RECYCLE_WORKERS_MAXTIME = 300;
    if (MASTER_RECREATE_WORKER_MAXTIME < 30 || MASTER_RECREATE_WORKER_MAXTIME > 300 )
        MASTER_RECYCLE_WORKERS_MAXTIME = 60;
    if (ServerConfig.databaseTimeout   < 50 || ServerConfig.databaseTimeout   > 1000)
        ServerConfig.databaseTimeout   = 50;

    MSG(LOG_INFO, "Worker[%d] has been reread the configuration", (int)getpid());
}

/**
  * @brief  重新载入CA
  * @param  void
  * @retval void
  */
void worker_reload_ca()
{
    int      i      = 0;
    int      rows   = -1;
    int      cols   = -1;
    BIO     *bio    = NULL;
    X509    *cacert = NULL;
    char    *errmsg = NULL;
    char     sqlBuffer[SQL_BUFLEN] = {0};

    X509_STORE_free(RootCertStore);

    /// get all name of CA path
    snprintf(sqlBuffer, SQL_BUFLEN, "SELECT CAFilter_path FROM tb_CAFilter");
    if (QueryDataFromDatabase(dbHandle, sqlBuffer, ServerConfig.caCertificatePath, rows, cols, errmsg) != SQLITE_OK)
        MSG(LOG_FATAL, "Query all name of CA path error %s!", errmsg);
    if (rows == 0)
        MSG(LOG_FATAL, "There is no certificate in the table of database!");
    ServerConfig.nCaCertificate = rows;

    /// import all ca certificate into X509 store
    if ((RootCertStore = X509_STORE_new()) == NULL)
        MSG(LOG_FATAL, "Fail to open the CertStore!");

    for (i=0; i<ServerConfig.nCaCertificate; i++)
    {
        ZeroMemory(sqlBuffer, SQL_BUFLEN);
        snprintf(sqlBuffer, SQL_BUFLEN, "%s%s.cer", "/sonicom/conf/openvpn/keys/", ServerConfig.caCertificatePath[i+1]);
        MSG_DEBUG("[03/12] SQL BUFFER IS : %s", sqlBuffer);

        if ((bio = BIO_new_file(sqlBuffer, "rt")) == NULL)
        {
            MSG(LOG_ERROR, "Certificate path error!");
            continue;
        }

        if ((cacert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL )
        {
            BIO_free(bio);
            MSG(LOG_ERROR, "Parse the certification error!");
            continue;
        }

        X509_STORE_add_cert(RootCertStore, cacert);
        BIO_free(bio);
        X509_free(cacert);
    }
    FreeQueryDataFromDatabase(ServerConfig.caCertificatePath);
    ServerConfig.caCertificatePath = NULL;

    MSG(LOG_INFO, "Worker[%d] has been reloaded the certificate authority", (int)getpid());
}

/**
  * @brief  重新载入CRL
  * @param  void
  * @retval void
  */
void worker_read_crl()
{
    BIO      *bio;
    X509_CRL *tempCertRevokeList;

    if ((bio = BIO_new_file(ServerConfig.certificateRevokeListPath, "r")) == NULL)
    {
        return;
    }
    if ((tempCertRevokeList = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) == NULL)
    {
        BIO_free(bio);
        return;
    }
    X509_CRL_free(CertRevokedList);
    CertRevokedList = tempCertRevokeList;

    MSG(LOG_INFO, "Worker[%d] has been reloaded the certificate revoke list", (int)getpid());
}

/**
  * @brief  迫使用户下线(数据格式:arg1;aa;bb;cc;)
  * @param  void
  * @retval void
  */
void worker_remove_client()
{
    int            i, j, msg;
    int            sharedMemoryLen;
    char           sharedTempBuffer[SHARED_TEMP_BUFLEN];
    char          *shmLogoffHead  = ShmLogoff;
    char          *shmLogoffBody  = ShmLogoff + SERVER_SHM_LF_HEAD_SIZE;
    CLIENT_DATA_T *currClientData = NULL;
    CLIENT_DATA_T *nextClientData = NULL;

    sharedMemoryLen = strlen(shmLogoffBody);
    if (sharedMemoryLen > SERVER_SHM_LF_BODY_SIZE)
        sharedMemoryLen = SERVER_SHM_LF_BODY_SIZE;

    /// 强迫全部用户下线
    MSG(LOG_INFO, "Worker[%d] is making client logoff!", WorkerProcess[WorkerProcessIndex].pid);
    if (strneql(shmLogoffBody, "all", 3))
    {
        currClientData = ClientDataManage.usedClientData->next;
        while (currClientData)
        {
            nextClientData = currClientData->next;
            if (currClientData->commonName)
                close_socket(currClientData, EVENT_OF_LOGOFF);
            currClientData = nextClientData;
        }
        goto tag_finish;
    }

    /// 根据参数强迫用户下线
    for (i=0, j=0; i<sharedMemoryLen; i++)
    {
        if (shmLogoffBody[i] != SPLIT[0])
        {
            sharedTempBuffer[j++] = shmLogoffBody[i];
            if (j == (SHARED_TEMP_BUFLEN - 1))
                j = 0;
        }
        else
        {
            sharedTempBuffer[j] = '\0';

            currClientData = ClientDataManage.usedClientData->next;
            while (currClientData)
            {
                nextClientData = currClientData->next;
                if (currClientData->commonName != NULL && streql(currClientData->commonName, sharedTempBuffer))
                {
                    close_socket(currClientData, EVENT_OF_LOGOFF);
                    break;
                }
                currClientData = nextClientData;
            }

            j = 0;
        }
    }

    /* please don't modify it unless you know what to do! */
tag_finish:
    ShmBusyRatioLock();
    snprintf(BusyRatioPtr[WorkerProcessIndex], SERVER_SHM_CT_PER_SIZE - 1, "%d",
             WorkerProcess[WorkerProcessIndex].busyRatio);
    ShmBusyRatioUnlock();
    msg = MW_BUSY_RATIO;
    send(WorkerProcess[WorkerProcessIndex].pipefd[1], &msg, 1, 0); // 不关心发送成功与否

    ShmLogoffLock();
    snprintf(shmLogoffHead, SERVER_SHM_LF_HEAD_SIZE - 1, "%d", atoi(shmLogoffHead) - 1);
    ShmLogoffUnlock();
}

/******************************* 关闭client socket *******************************/
/**
  * @brief  关闭socket
  * @param  arg1:用户数据   arg2:event
  * @retval NULL
  */
void close_socket(CLIENT_DATA_T *clientData, int event)
{
    char *errmsg                = NULL;
    char  dotip[16]             = {0};
    char  timeBuffer[32]        = {0};
    char  sqlBuffer[SQL_BUFLEN] = {0};

    /// 清除登录标记
    ZeroMemory(sqlBuffer, SQL_BUFLEN);
    snprintf(sqlBuffer, SQL_BUFLEN,
                "UPDATE MPSInfo SET processId = 0, loginState = \'0\', userLogoffTime = \'%s\' "
                "WHERE userName = \'%s\'",
                get_system_date(timeBuffer, 1),
                clientData->commonName);
    if (UpdateDataFromDatabase(dbHandle, sqlBuffer, errmsg) != SQLITE_OK)
    {
        MSG(LOG_ERROR, "Clear loginstate flag error, %s", errmsg);
        sqlite3_free(errmsg);
    }

    ///***pathced by xiaohu add**2016/07/04
    //南阳特殊需求，表没有建立，故不使用此功能
    ///尝试在此加入日志记录，掉线时候江最后记录选出并且以新纪录的方式插入新日志表，有必要的话进行回滚
    ///由于掉线不是高发事件，所以可以在此回滚一个月的日志
    /*
    MSG(LOG_INFO, "[07/04]INSERT INTO MPSInfo_log SELECT * FROM MPSInfo");
    ZeroMemory(sqlBuffer, SQL_BUFLEN);
    snprintf(sqlBuffer, SQL_BUFLEN,
                "INSERT INTO MPSInfo_log SELECT * FROM MPSInfo "
                "WHERE userName = \'%s\'",
                clientData->commonName);
    if (UpdateDataFromDatabase(dbHandle, sqlBuffer, errmsg) != SQLITE_OK)
    {
        MSG(LOG_ERROR, "insert the mpsinfo_log table error, %s", errmsg);
        sqlite3_free(errmsg);
    }

    MSG(LOG_INFO, "[07/04]roll back MPSInfo_log WHERE DATE('now','-1 months')>DATE(userlogofftime)");
    ZeroMemory(sqlBuffer, SQL_BUFLEN);
    snprintf(sqlBuffer, SQL_BUFLEN,
                "DELETE FROM MPSInfo_log WHERE DATE('now','-1 months')>DATE(userlogofftime)");
    if (UpdateDataFromDatabase(dbHandle, sqlBuffer, errmsg) != SQLITE_OK)
    {
        MSG(LOG_ERROR, "insert the mpsinfo_log table error, %s", errmsg);
        sqlite3_free(errmsg);
    }*/
    ///**************************2016/07/04

    /// 关闭iptable
    if (clientData->iptableFlag == 1)
    {
        valip_to_dotip(dotip, clientData->ipAddress);
        snprintf(sqlBuffer, SQL_BUFLEN,
                "iptables -D STUNNELDEFINED -s %s/32 -p tcp -j TCP_ALLOWED; "
                "iptables -D STUNNELDEFINED -s %s/32 -j ACCEPT",
                dotip, dotip);
        system(sqlBuffer);
        clientData->iptableFlag = 0;
    }

    /// openvpn端口均衡
    if (clientData->vpnPortIndex > 0)
    {
        VPNPortCount[clientData->vpnPortIndex-1]--;
        clientData->vpnPortIndex = 0;
    }

    /// 释放CN内存
    if (clientData->commonName)
    {
        free(clientData->commonName);
        clientData->commonName = NULL;
    }

    /// 释放sockBuffer
    if (clientData->sockBuffer)
    {
        free_sock_buffer(&SockBufferManage, clientData->sockBuffer);
        clientData->sockBuffer = NULL;
    }

    /// 释放fileInfo
    if (clientData->fileInfo.filefd > 0)
    {
        close(clientData->fileInfo.filefd);
        clientData->fileInfo.filefd = 0;
    }
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.buffer = NULL;
    }
    clientData->fileInfo.length   = 0;
    clientData->fileInfo.position = 0;

    /// 关闭socket
    close_fd(Epollfd, clientData->sockfd);
    if (event == EVENT_OF_TIMER)
    {
        free_client_data(&ClientDataManage, clientData);
        if (WorkerProcess[WorkerProcessIndex].busyRatio > 0)
            WorkerProcess[WorkerProcessIndex].busyRatio--;
        MSG_DEBUG("Closing socket by heartbeat timeout!");
    }
    else if (event == EVENT_OF_LOGOFF)
    {
        delete_timer(&clientData->timer);
        free_client_data(&ClientDataManage, clientData);
        if (WorkerProcess[WorkerProcessIndex].busyRatio > 0)
            WorkerProcess[WorkerProcessIndex].busyRatio--;
        MSG_DEBUG("Closing socket by making client logoff!");
    }
    else
    {
        delete_timer(&clientData->timer);
        MSG_DEBUG("Closing socket by local or foreign host!");
    }
}

/******************************* Worker进程接收客户请求发送响应 *******************************/
/**
  * @brief  发送hearbeat响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_heartbeat_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

//    IsShutdown();

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d", 4, IDX_VPN_HEARTBEAT);;
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}

/**
  * @brief  发送hearbeat时间间隔响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_heartbeat_timeout_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%4d", 8, IDX_VPN_HEARTBEAT_TIMEOUT, WORKER_HEARTBEAT_TIMEOUT);;
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}

/**
  * @brief  发送utunnel响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_utunnel_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_UTUNNEL, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}

/**
  * @brief  发送stunnel响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_stunnel_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_STUNNEL, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}

/**
  * @brief  发送openvpn响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_openvpn_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    char    buffer[SQL_BUFLEN] = {0};
    MSG_DEBUG("send_openvpn_response_cb 1111111111111111\n");

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        snprintf(buffer, SQL_BUFLEN, "%4d%4d%5d:%s", (int)strlen(OpenvpnConfig) + 10,
                 IDX_VPN_OPENVPN, 61193+clientData->vpnPortIndex, OpenvpnConfig);
        MSG_DEBUG("send_openvMSG_DEBUGpn_response_cb %s\n", buffer);
        clientData->fileInfo.buffer = (u_char *)strdup(buffer);
        if (clientData->fileInfo.buffer == NULL)
            goto tag_close_socket;
        clientData->fileInfo.length = strlen(buffer);
        clientData->fileInfo.position = 0;
    }
    MSG_DEBUG("send_openvpn_response_cb 22222222222222\n");
    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    MSG_DEBUG("send_openvpn_response_cb 3333333333333333\n");
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}
//****************patched by yagamishi add*************2016/01/28*******
//******************按进程判断是否启动*****************************
/**
  * @brief  发送process响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_process_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_PROCESS, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}
//*********************************************************************

//****************patched by yagamishi add*************2016/02/03*******
//******************按手机型号判断是否启动*****************************
/**
  * @brief  发送android_type响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_android_type_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_ANDROID_TYPE, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}
//*********************************************************************

///****************patched by yagamishi add*************2016/02/10*******
///******************检查正在运行的东西是否符合规则*****************************
/**
  * @brief  发送check_running响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_check_running_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_CHECK_RUNNING, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}
///*********************************************************************
///****************patched by yagamishi add*************2016/02/17*******
/**
  * @brief  发送check_running_switch响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_check_running_switch_response_cb(CLIENT_DATA_T *clientData)
{
     int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_CHECK_RUNNING_SWITCH, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}

/**
  * @brief  发送android_check_switch响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_android_check_switch_response_cb(CLIENT_DATA_T *clientData)
{
     int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_AD_CHECK_SWITCH, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}

/**
  * @brief  发送android_check_running_switch响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_android_check_running_switch_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_AD_CHECK_RUNNING_SWITCH, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}
///*************************************************************************
///****************patched by yagamishi add*************2016/02/18*******
///******************发送日志回执********************************************/
/**
  * @brief  发送log回执
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_log_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4dlogok", 9, IDX_VPN_ZDJG_LOG);
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}
///*************************************************************************************
///****************patched by yagamishi add*************2016/02/26*******
/**
  * @brief  发送androidTypeDoor回执
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
  int send_android_type_door_response_cb(CLIENT_DATA_T *clientData)
{
    int     retval             = RETURN_FAILURE;
    int     length             = 0;
    char   *tempBufPtr         = NULL;

    if (clientData->commomFlag == 0)
    {
        clientData->commomFlag = 1;
        length = strlen((char *)clientData->fileInfo.buffer) + 9;
        tempBufPtr = (char *)calloc(length, 1);
        if (tempBufPtr == NULL)
            goto tag_close_socket;
        snprintf(tempBufPtr, length, "%4d%4d%s", length-5, IDX_VPN_ANDROID_DOOR, clientData->fileInfo.buffer);
        free(clientData->fileInfo.buffer);

        clientData->fileInfo.buffer = (u_char *)tempBufPtr;
        clientData->fileInfo.length = strlen(tempBufPtr);
        clientData->fileInfo.position = 0;
    }

    while (TRUE)
    {
        retval = send(clientData->sockfd,
                      clientData->fileInfo.buffer + clientData->fileInfo.position,
                      clientData->fileInfo.length - clientData->fileInfo.position,
                      0);
        if (retval < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback((CLIENT_EVENT_T *)__FUNCTION__, EPOLLOUT);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        clientData->fileInfo.position += retval;
        if (clientData->fileInfo.position < clientData->fileInfo.length)
        {
            continue;
        }
        else if (clientData->fileInfo.position == clientData->fileInfo.length)
        {
            SetCallback(recv_requests_cb, EPOLLIN);
            retval = RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

tag_close_socket :
    if (clientData->fileInfo.buffer)
    {
        free(clientData->fileInfo.buffer);
        clientData->fileInfo.length   = 0;
        clientData->fileInfo.position = 0;
        clientData->fileInfo.buffer   = NULL;
    }
    clientData->commomFlag = 0;

    return retval;
}

///*************************************************************************************
/**
  * @brief  发送apptype响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_apptype_response_cb(CLIENT_DATA_T *clientData)
{
    int         retval;
    int         sendDataSize;
    int         sendDataPosition;
    char        sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};
    PACK_HEAD_T packHead;

    IsShutdown();

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        switch (ServerConfig.appType)
        {
            case 1: packHead = IDX_VPN_OPENVPN; break;
            case 2: packHead = IDX_VPN_STUNNEL; break;
            case 3: packHead = IDX_VPN_BOTH; break;
            default : packHead = IDX_VPN_NONE; break;
        }
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%4d", 8, IDX_VPN_APPTYPE, packHead);
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}

/**
  * @brief  发送bind响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_bind_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

    IsShutdown();

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%s", 6, IDX_VPN_BIND, SERVER_POSITIVE);
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}

/**
  * @brief  发送SN响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_sn_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

    IsShutdown();

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%s", 6, IDX_VPN_SN, SERVER_POSITIVE);
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}

/**
  * @brief  发送X509响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_x509_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

    IsShutdown();

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%s", 6, IDX_VPN_X509, SERVER_POSITIVE);
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    SendCommand(clientData, recv_requests_cb);
}

/**
  * @brief  接收X509请求
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int recv_requests_of_x509_cb(CLIENT_DATA_T *clientData)
{
    int             retval;
    CERTIFICATE_T  *certificate;

    /// 预读数据长度
    certificate = (CERTIFICATE_T *)clientData->sockBuffer;
    if (certificate == NULL)
    {
        certificate = get_certificate(&CertificateManage);
        if (certificate == NULL)
        {
            certificate = (CERTIFICATE_T *)calloc(1, sizeof(CERTIFICATE_T));
            if (certificate == NULL)
                goto tag_close_socket;
            clientData->certpool = YES;
        }
        clientData->sockBuffer = (SOCK_BUFFER_T *)certificate;

tag_head :
        retval = recv(clientData->sockfd, certificate->buffer, CLIENT_DATA_PACK_HEADLEN, 0);
        if (retval < 0)
        {
            if (errno == EINTR)
                goto tag_head;
            else
                goto tag_close_socket;
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        certificate->bufferPosition = 0;
        if ( (retval != CLIENT_DATA_PACK_HEADLEN) ||
             ((certificate->bufferLength = atoi((char *)certificate->buffer)) == 0) )
        {
            MSG(LOG_ERROR, "[recv_requests_of_x509_cb:] Getting the size of datapack is error!");
            goto tag_close_socket;
        }
    }

    ///  根据数据长度接受数据
    ZeroMemory(certificate->buffer, CERTIFICATE_BUFFERLEN);
    while (TRUE)
    {
        retval = recv(clientData->sockfd,
                      certificate->buffer +
                      certificate->bufferPosition,
                      certificate->bufferLength -
                      certificate->bufferPosition, 0);
        if (retval <0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback(recv_requests_of_x509_cb, EPOLLIN);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        certificate->bufferPosition += retval;
        if (certificate->bufferPosition < certificate->bufferLength)
        {
            continue;
        }
        else if (certificate->bufferPosition == certificate->bufferLength)
        {
            if (verify_certificate(clientData) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_x509_response_cb, EPOLLOUT);

            if (clientData->certpool == NO)
            {
                free_certificate(&CertificateManage, certificate);
            }
            else
            {
                free(certificate);
                clientData->certpool = NO;
            }
            clientData->sockBuffer = NULL;
            return RETURN_SUCCESS;
        }
        else
        {
            goto tag_close_socket;
        }
    }

    /// 关闭socket
tag_close_socket :
    if (certificate)
    {
        if (clientData->certpool == NO)
        {
            free_certificate(&CertificateManage, certificate);
        }
        else
        {
            free(certificate);
            clientData->certpool = NO;
        }
        clientData->sockBuffer = NULL;
    }
    close_socket(clientData, EVENT_OF_CLIENT);
    return RETURN_FAILURE;
}

/**
  * @brief  发送登录响应
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_version_response_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    int  sendDataSize;
    int  sendDataPosition;
    char sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};

    IsShutdown();

    if (clientData->sockBuffer == NULL)
    {
        /*唯一可以添加代码处*/
        /* clientData->fileInfo.filefd equals 1 update, or do not update */
        if (clientData->fileInfo.filefd)
            snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%s", 10, IDX_VPN_VERSION, "update");
        else
            snprintf(sockBuffer, CLIENT_SOCK_RECV_MAXBUF, "%4d%4d%s", 12, IDX_VPN_VERSION, "noupdate" );
        clientData->fileInfo.filefd = 0;
        sendDataSize = strlen(sockBuffer);
        sendDataPosition = 0;
    }
    //SendCommand(clientData, recv_requests_of_x509_cb);    //orig
    SendCommand(clientData, recv_requests_cb);              //for linux client
}

/**
  * @brief  从客户端接收数据并且解析头部
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int recv_requests_cb(CLIENT_DATA_T *clientData)
{
    int             retval;
    int             recvDataSize;
    char            tempBuffer[SERVER_TEMP_BUFLEN] = {0};
    unsigned char   sockBuffer[CLIENT_SOCK_RECV_MAXBUF] = {0};
    DATA_PACK_T    *dataPack = (DATA_PACK_T *)sockBuffer;

    /// 预读数据长度
    if (clientData->sockBuffer == NULL)
    {
tag_head :
        retval = recv(clientData->sockfd, tempBuffer, CLIENT_DATA_PACK_HEADLEN, 0);
        if (retval <0)
        {
            if (errno == EINTR)
                goto tag_head;
            else
                goto tag_close_socket;
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        if ( (retval != CLIENT_DATA_PACK_HEADLEN) || ((recvDataSize = atoi(tempBuffer)) == 0) )
        {
            MSG(LOG_ERROR, "[recv_request_of_client_cb:] Getting the size of datapack is error!");
            goto tag_close_socket;
        }
    }
    else
    {
        recvDataSize = clientData->sockBuffer->bufferLength -
                       clientData->sockBuffer->bufferPosition;
    }

    /// 根据数据长度读取数据
    while (TRUE)
    {
        ZeroMemory(sockBuffer, CLIENT_SOCK_RECV_MAXBUF);
        retval = recv(clientData->sockfd, sockBuffer, recvDataSize, 0);
        if (retval <0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                SetCallback(recv_requests_cb, EPOLLIN);
                return RETURN_SUCCESS;
            }
            else
            {
                goto tag_close_socket;
            }
        }
        else if (retval == 0)
        {
            goto tag_close_socket;
        }

        recvDataSize -= retval;
        if (recvDataSize == 0)
        {
            if (clientData->sockBuffer != NULL)
            {
                memcpy(clientData->sockBuffer->buffer +
                       clientData->sockBuffer->bufferPosition,
                                   sockBuffer, retval);
                memcpy(sockBuffer,
                       clientData->sockBuffer->buffer,
                       clientData->sockBuffer->bufferLength);
                free_sock_buffer(&SockBufferManage, clientData->sockBuffer);
                clientData->sockBuffer = NULL;
            }

            strncpy((char *)tempBuffer, (const char *)sockBuffer, 4);
            dataPack->head = atoi(tempBuffer);
            goto tag_parse_content;
        }
        else if (recvDataSize > 0)
        {
            if (clientData->sockBuffer == NULL)
            {
                clientData->sockBuffer = get_sock_buffer(&SockBufferManage);
                if (clientData->sockBuffer == NULL)
                    goto tag_close_socket;
                clientData->sockBuffer->bufferLength = recvDataSize + retval;
            }
            memcpy(clientData->sockBuffer->buffer +
                   clientData->sockBuffer->bufferPosition,
                               sockBuffer, retval);
            clientData->sockBuffer->bufferPosition += retval;
        }
        else
        {
            goto tag_close_socket;
        }
    } // end of while

    /// 数据解析
tag_parse_content :
    switch (dataPack->head)
    {
        case IDX_VPN_VERSION :
            handle_version(clientData, (char *)dataPack->buffer);
            SetCallback(send_version_response_cb, EPOLLOUT);
            break;
        ///****************patched by yagamishi add*************2016/02/18*******
        ///******************发送日志********************************************
        case IDX_VPN_ZDJG_LOG :
            MSG_DEBUG("[h] dataPack -> buffer%s \n",(char *)dataPack->buffer);
            if (zdjg_write_to_db(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_log_response_cb, EPOLLOUT);
            break;
        ///*************************************************************************
        ///****************patched by yagamishi add*************2016/01/28*******
        ///******************按进程判断是否启动*****************************
        case IDX_VPN_PROCESS :
            clientData->fileInfo.buffer = (u_char *)calloc( strlen(check_pre_proc_win_buf), sizeof(char*) );
            strcpy((char *)clientData->fileInfo.buffer, check_pre_proc_win_buf);
            SetCallback(send_process_response_cb, EPOLLOUT);
            break;
        ///*********************************************************************
        ///****************patched by yagamishi add*************2016/02/03*******
        ///******************按手机型号判断是否启动*****************************
        case IDX_VPN_ANDROID_TYPE :
            clientData->fileInfo.buffer = (u_char *)calloc( strlen(check_pre_type_and_buf), sizeof(char*) );
            strcpy((char *)clientData->fileInfo.buffer, check_pre_type_and_buf);
            SetCallback(send_android_type_response_cb, EPOLLOUT);
            break;
        ///*********************************************************************
        ///****************patched by yagamishi add*************2016/02/10*******
        ///******************检查正在运行的东西是否符合规则*****************************
        case IDX_VPN_CHECK_RUNNING :
            clientData->fileInfo.buffer = (u_char *)calloc(strlen(check_run_proc_win_buf), sizeof(char*));
            strcpy((char *)clientData->fileInfo.buffer, check_run_proc_win_buf);
            SetCallback(send_check_running_response_cb, EPOLLOUT);
            break;
        ///*********************************************************************
        ///****************patched by yagamishi add*************2016/02/17*******
        case IDX_VPN_CHECK_RUNNING_SWITCH :
            if (generate_check_running_switch_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_check_running_switch_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_AD_CHECK_SWITCH :
            if (generate_android_check_switch_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_android_check_switch_response_cb, EPOLLOUT);
            break;
        case IDX_VPN_AD_CHECK_RUNNING_SWITCH :
            if (generate_android_check_running_switch_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_android_check_running_switch_response_cb, EPOLLOUT);
            break;
        ///*************************************************************************
        ///*********************************************************************
        ///****************patched by yagamishi add*************2016/02/26*******
        case IDX_VPN_ANDROID_DOOR :
            MSG_DEBUG("[02/26]%s\n", "epoll_in android door event");
            if (generate_android_type_door_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            MSG_DEBUG("[02/26]%s\n", "epoll_in android door set callback now");
            SetCallback(send_android_type_door_response_cb, EPOLLOUT);
            break;
        ///*************************************************************************
/*      case IDX_VPN_X509 :
            break; */

        case IDX_VPN_SN :
            if (verify_certificate_revoke_list(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_sn_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_BIND :
            if (verify_bind_constraint(clientData, (char *)dataPack->buffer,ServerConfig.pmos) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_bind_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_APPTYPE :
            //****************patched by yagamishi add*************2015/8/17*******
            generate_iptables(clientData);
            //*********************************************************************
            SetCallback(send_apptype_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_OPENVPN :
            MSG_DEBUG("IDX_VPN_OPENVPN event");
            if (generate_openvpn_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_openvpn_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_STUNNEL :
            if (generate_stunnel_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_stunnel_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_UTUNNEL :
            if (generate_utunnel_config(clientData, (char *)dataPack->buffer) == RETURN_FAILURE)
                goto tag_close_socket;
            SetCallback(send_utunnel_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_HEARTBEAT_TIMEOUT :
            SetCallback(send_heartbeat_timeout_response_cb, EPOLLOUT);
            break;

        case IDX_VPN_HEARTBEAT :
            clientData->nLostHeartBeat = 1;
            AdjustTimer();
            SetCallback(send_heartbeat_response_cb, EPOLLOUT);
            break;

        default :
            goto tag_close_socket;
    }
    return RETURN_SUCCESS;

    /// 关闭socket
tag_close_socket :
    close_socket(clientData, EVENT_OF_CLIENT);
    return RETURN_FAILURE;
}

/**
  * @brief  发送客户欢迎请求
  * @param  arg1:用户数据
  * @retval 成功返回RETURN_SUCCESS, 否则RETURN_FAILURE
  */
int send_welcome_response_cb(CLIENT_DATA_T *clientData)
{
    int retval;

    IsShutdown();

    if ( (retval = send(clientData->sockfd, SERVER_POSITIVE, 2, 0)) == 2 )
    {
        clientData->nLostHeartBeat = 1;
        AdjustTimer();
        SetCallback(recv_requests_cb, EPOLLIN);
        return RETURN_SUCCESS;
    }

tag_close_socket :
    close_socket(clientData, EVENT_OF_CLIENT);
    return RETURN_FAILURE;
}

/**
  * @brief  接收客户欢迎请求
  * @param  arg1:用户数据
  * @retval RETURN_SUCCESS
  */
int recv_welcome_request_cb(CLIENT_DATA_T *clientData)
{
    int  retval;
    char sockBuffer[SERVER_TEMP_BUFLEN] = {0};

    retval = recv(clientData->sockfd, sockBuffer, SERVER_TEMP_BUFLEN, 0);
    if (retval == SERVER_PSWDSIZE && strneql(sockBuffer, SERVER_PASSWORD, SERVER_PSWDSIZE))
    {
        clientData->shutdown = NO;
    }
    else
    {
        clientData->shutdown = YES;
    }
    SetCallback(send_welcome_response_cb, EPOLLOUT);

    return RETURN_SUCCESS;
}

/******************* (C) COPYRIGHT 2014 上海今中网络科技有限公司 *****END OF FILE****/





